import json

from django_filters import rest_framework as filters
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from weixin import WXAPPAPI
from weixin.oauth2 import OAuth2AuthExchangeError

from jiaozi.base_view import JwtCreateAPIView, JwtListCreateAPIView, \
    JwtRetrieveUpdateDestroyAPIView
from jiaozi.sms_aliyun import aliyun_send_sms
from jiaozi.utils import generate_code, MmFilter, APIResponse, file_field_to_link
from product.models import Banner, ProductSales, ProductBatch, ProductInfo, ProductStyle, HotSearch
from vip.models import VipSalesOrder, VipSales
from vip.views import get_user_id
from .serializers import *


class AppFilter(filters.FilterSet):

    @classmethod
    def filter_for_field(cls, field, field_name, lookup_expr='exact'):
        filter_class = super().filter_for_field(field, field_name, lookup_expr)
        if lookup_expr == 'exact':
            filter_class.extra['help_text'] = '{0} 等于'.format(field.verbose_name)
        elif lookup_expr == 'contains':
            filter_class.extra['help_text'] = '{0} 包含'.format(field.verbose_name)
        elif lookup_expr == 'gte':
            filter_class.extra['help_text'] = '{0} 大于等于'.format(field.verbose_name)
        elif lookup_expr == 'gt':
            filter_class.extra['help_text'] = '{0} 大于'.format(field.verbose_name)
        elif lookup_expr == 'lt':
            filter_class.extra['help_text'] = '{0} 小于'.format(field.verbose_name)
        elif lookup_expr == 'lte':
            filter_class.extra['help_text'] = '{0} 小于等于'.format(field.verbose_name)
        return filter_class


def get_user_info_by_openid(openid, unionid):
    wx_user = {}
    access_token = None
    if openid:
        wx_user, create = WxUser.objects.get_or_create(openid=openid)
        if unionid:
            if wx_user.unionid != unionid:
                wx_user.unionid = unionid
                wx_user.save()
        access_token = str(TokenObtainPairSerializer.get_token(wx_user).access_token)
    return wx_user, access_token


class FeedBackCreateView(JwtCreateAPIView):
    """
    用户反馈的提交
    """
    permission_classes = ()
    serializer_class = FeedBackSerializer

    def create(self, request, *args, **kwargs):
        new_data = dict()
        for k, v in request.data.items():
            new_data[k] = v
        user_id = get_user_id(self)
        new_data['user'] = user_id
        serializer = self.get_serializer(data=new_data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, headers=headers)


class BindMobileView(GenericAPIView):
    """
    绑定手机号。
    """
    serializer_class = BindMobileSerializer

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        request_data = serializer.validated_data
        mobile = request_data.get('mobile')
        code = request_data.get('code')
        res = check_mobile_code(mobile, code)
        if not res:
            return APIResponse(message='短信验证码错误或已过期', code=400)
        user_id = get_user_id(self)
        if user_id:
            wx_user = WxUser.objects.get(pk=user_id)
            wx_user.mobile = mobile
            wx_user.save()
            return APIResponse(message='绑定成功', data=get_user_info(wx_user))
        else:
            return APIResponse(message='账号未登录', code=400)


class GetCodeView(GenericAPIView):
    """
    发送手机号获取验证码。
    """
    permission_classes = ()
    serializer_class = GetCodeSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        request_data = serializer.validated_data
        mobile = request_data.get('mobile')
        send_time = datetime.datetime.now() - datetime.timedelta(minutes=1)
        last_24h = datetime.datetime.now() - datetime.timedelta(hours=24)
        pre_send = SmsRecord.objects.filter(mobile=mobile, datetime_created__gte=send_time)
        # 说明最近一分钟有发送记录
        if pre_send.exists():
            return APIResponse(message='短信已发送，请稍后重试', code=400)
        last_24h_send = SmsRecord.objects.filter(mobile=mobile, datetime_created__gte=last_24h).count()
        if last_24h_send > 5:
            return APIResponse(message='短信已发送次数已经超限', code=400)
        code = generate_code()
        para = {"code": '{}'.format(code)}
        res = aliyun_send_sms(mobile=mobile, para=json.dumps(para))
        # 添加发送记录
        if res:
            SmsRecord.objects.create(mobile=mobile, code=code, is_active=True)
            return APIResponse(message='验证码发送成功')
        else:
            return APIResponse(message='验证码发送失败', code=400)


class HomePageView(APIView):
    """
    小程序首页接口，不管用户是否登录都可以获取数据。
        banners: 顶部广告页信息，product_sales_id 为跳转在售产品页面的 id；
        new_products: 新产品，id 为跳转在售产品页面的 id；
        cooperation: 合作厂家的产品；
        hot_products: 热门产品；
        user_info: 用户信息，包含用户是否是 VIP 等信息；
        images: 首页的图片元素。
    """
    permission_classes = ()

    @staticmethod
    def get_product_info(current_product):
        current_product['product_batch'] = model_data_from_cache(
            ProductBatch, current_product.get('product_batch')
        )
        current_product['product_batch']['product_info'] = model_data_from_cache(
            ProductInfo, current_product['product_batch']['product_info']
        )
        product_style = current_product['product_batch']['product_info']['product_style']
        if product_style:
            current_product['product_batch']['product_info']['product_style'] = model_data_from_cache(
                ProductStyle, product_style
            )
        else:
            current_product['product_batch']['product_info']['product_style'] = {}
        return current_product

    def get(self, request):
        res_data = {
            'banners': [],
            'new_products': [],
            'cooperation': [],
            'hot_products': [],
            'user_info': {
                'id': 0,
                "openid": None,
                "unionid": None,
                "nick_name": "",
                "gender": None,
                "date_of_birth": None,
                "vip_level": None,
                "vip_start": None,
                "vip_end": None,
                "default_user_address": None
            },
            'images': {
                'logo_circular': '',
                'logo_square': '',
                'image_1': '',
                'image_2': '',
                'image_3': '',
                'image_4': '',
                'image_5': '',
                'vip_background': '',
            }
        }
        current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        # 获取 banners
        banners = Banner.objects.filter(
            is_show=True,
            show_start__lte=current_time,
        ).order_by('order_index', 'pk')
        for banner in banners:
            res_data['banners'].append(convert_obj_to_dict(banner, fields=['banner_image', 'jump_url']))

        # 获取 new_products
        new_product_sales = ProductSales.objects.filter(
            is_show=True,
            show_start__lte=current_time,
            sales_end__gte=current_time,
        ).order_by('-sales_start')[:6]
        new_products = list()
        for new_product_sale in new_product_sales:
            current_product = convert_obj_to_dict(new_product_sale, exclude=['is_show', 'show_start'])
            current_product = self.get_product_info(current_product)
            new_products.append(current_product)

        res_data['new_products'] = new_products

        for product_category__name_en in ['hot_products', 'cooperation']:

            current_category_product_sales = ProductSales.objects.filter(
                product_category__name_en=product_category__name_en
            ).filter(
                is_show=True,
                show_start__lte=current_time,
                sales_end__gte=current_time,
            ).order_by('order_index', '-sales_start')[:6]

            current_category_products = list()
            for current_category_product_sale in current_category_product_sales:
                current_product = convert_obj_to_dict(current_category_product_sale, exclude=['is_show', 'show_start'])
                current_product = self.get_product_info(current_product)
                current_category_products.append(current_product)
            res_data[product_category__name_en] = current_category_products

        # user_info
        user_id = get_user_id(self)
        if user_id:
            user_info = WxUser.objects.filter(pk=user_id).values(
                'id', 'openid', 'unionid', 'nick_name', 'gender', 'date_of_birth', 'vip_level',
                'vip_start', 'vip_end', 'default_user_address',
            ).first()
            res_data['user_info'] = user_info
        # 获取首页配置信息
        images = WxHome.objects.filter(is_active=True).order_by('pk').first()
        if images:
            res_data['images'] = convert_obj_to_dict(images)
        return APIResponse(data=res_data)


class UserAddressFilter(MmFilter):
    class Meta:
        model = UserAddress
        fields = {
            'address': ['contains'],
            'area': ['contains'],
            'mobile': ['contains']
        }


class UserAddressListCreateView(JwtListCreateAPIView):
    """
    get:
        用户地址的获取
    post:
        用户地址创建或更新
    """
    serializer_class = UserAddressSerializer
    filterset_class = UserAddressFilter
    queryset = None
    pagination_class = None

    def get_queryset(self):
        queryset = UserAddress.objects.none()
        user_id = get_user_id(self)
        if user_id:
            queryset = UserAddress.objects.filter(user_id=user_id)
        return queryset

    def create(self, request, *args, **kwargs):
        new_data = dict()
        for k, v in request.data.items():
            new_data[k] = v
        # 添加默认值 user 为提交的用户
        user_id = get_user_id(self)
        new_data['user'] = user_id
        instance = UserAddress.objects.filter(user_id=user_id).order_by('pk').last()
        if not instance:
            serializer = self.get_serializer(data=new_data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
        else:
            partial = kwargs.pop('partial', False)
            serializer = self.get_serializer(instance, data=new_data, partial=partial)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            if getattr(instance, '_prefetched_objects_cache', None):
                instance._prefetched_objects_cache = {}
        return APIResponse(data=serializer.data)


class UserAddressRetrieveUpdateAPIView(JwtRetrieveUpdateDestroyAPIView):
    """
    get:
        地址获取
    put:
        地址全局更新
    patch:
        地址部分更新
    """
    serializer_class = UserAddressSerializer
    queryset = None

    def get_queryset(self):
        queryset = UserAddress.objects.none()
        user_id = get_user_id(self)
        if user_id:
            queryset = UserAddress.objects.filter(user_id=user_id)
        return queryset


def convert_datetime_to_timestamp(dt):
    res = 0
    if dt:
        if isinstance(dt, datetime.datetime):
            res = int_value(dt.timestamp())
        if isinstance(dt, str):
            res = int_value(datetime.datetime.strptime(dt, '%Y-%m-%d %H:%M:%S').timestamp())
    return res


class VipInfoView(APIView):
    """
    用户得VIP 信息获取。
        vip_start: 当前 VIP 开始时间戳，如果是0，代表没有；
        vip_end：当前 VIP 截止时间戳，如果是0，代表没有；
        vip_level：当前 VIP 等级，如果是0，代表没有；
        vip_orders：VIP 的购买记录。
    """

    def get(self, request):
        data = {
            'svip_start': 0,
            'svip_end': 0,
            'gvip_start': 0,
            'gvip_end': 0,
            'vip_orders': []
        }
        user_id = get_user_id(self)
        if user_id:
            vip_orders = list(VipSalesOrder.objects.filter(
                user_id=user_id, is_payed=True
            ).order_by('datetime_created').values(
                'order_number',
                'vip_sales_id',
                'vip_sales__vip_level__level_name',
                'vip_sales__main_image',
                'vip_sales__vip_start',
                'vip_sales__vip_end',
                'price_initial',
                'price_payed',
                'is_payed',
            ))
            data['vip_orders'] = vip_orders

            for vip_order in vip_orders:
                vip_sales_id = vip_order['vip_sales_id']
                vip_sales = model_data_from_cache(VipSales, pk=vip_sales_id)
                vip_start = convert_datetime_to_timestamp(vip_sales['vip_start'])
                vip_end = convert_datetime_to_timestamp(vip_sales['vip_end'])
                level_name = str(vip_order['vip_sales__vip_level__level_name']).lower()
                if level_name == 'gvip':
                    if not data['gvip_start']:
                        data['gvip_start'] = vip_start
                    if vip_end > data['gvip_end']:
                        data['gvip_end'] = vip_end
                elif level_name == 'svip':
                    if not data['svip_start']:
                        data['svip_start'] = vip_start
                    if vip_end > data['svip_end']:
                        data['svip_end'] = vip_end
                vip_order['vip_sales__main_image'] = file_field_to_link(vip_order['vip_sales__main_image'])

        return APIResponse(data=data, code=200)


class WxLoginView(GenericAPIView):
    """
    通过 code 进行登录，返回 access_token
    """
    authentication_classes = []
    permission_classes = []
    serializer_class = LoginSerializer

    def post(self, request):
        code = request.data.get('code')
        if code:
            api = WXAPPAPI(appid=settings.WX_APP_ID, app_secret=settings.WX_APP_SECRET)
            try:
                session_info = api.exchange_code_for_session_key(code=code)
            except OAuth2AuthExchangeError:
                session_info = None
            if session_info:
                openid = session_info.get('openid', None)
                unionid = session_info.get('unionid', None)
                wx_user, access_token = get_user_info_by_openid(openid, unionid)
                data = {
                    'user': get_user_info(wx_user),
                    'session_info': session_info,
                    'access_token': access_token,
                }
                return APIResponse(data=data, code=200)
        return APIResponse(code=400)


class MobileLoginView(GenericAPIView):
    """
    通过 手机号和验证码 进行登录，返回 access_token
    """
    authentication_classes = []
    permission_classes = []
    serializer_class = MobileLoginSerializer

    def post(self, request):
        mobile = request.data.get('mobile')
        code = request.data.get('code')
        if mobile and code:
            if check_mobile_code(mobile, code):
                wx_user = WxUser.objects.filter(mobile=mobile).order_by('pk').first()
                if wx_user:
                    access_token = str(TokenObtainPairSerializer.get_token(wx_user).access_token)
                    data = {
                        'user': get_user_info(wx_user),
                        'access_token': access_token,
                    }
                    return APIResponse(data=data, code=200)
            else:
                return APIResponse(message='验证码错误或已过期', code=400)
        return APIResponse(code=400)


class GetDocView(GenericAPIView):
    """
    通过 key_word 获取文章内容
    """
    authentication_classes = []
    permission_classes = []
    serializer_class = GetDocSerializer

    def post(self, request):
        key_word = request.data.get('key_word')
        data = {
            'title': '',
            'body': '',
            'datetime_created': '',
            'datetime_updated': '',

        }
        if key_word:
            data = Document.objects.filter(key_word=key_word, is_active=True).order_by('pk').values().first()
        return APIResponse(data=data, code=200)


class GetHotSearchView(GenericAPIView):
    """
    获取热门搜索
    """
    authentication_classes = []
    permission_classes = []
    serializer_class = GetDocSerializer
    pagination_class = None

    def get(self, request):
        res = HotSearch.objects.filter(is_show=True).order_by('-count').values('key_word', 'count')
        data = list()
        count = 0
        for row in res:
            if count >= 5:
                break
            data.append(row)
            count += 1
        return APIResponse(data=data, code=200)


class UserInfoView(GenericAPIView):
    """
    用户信息的获取和更新
    """
    serializer_class = WxUserSerializer
    pagination_class = None
    filter_backends = ()

    def get(self, request):
        user_id = get_user_id(self)
        data = {
            "nick_name": "",
            "mobile": None,
            "date_of_birth": None,
            "gender": None
        }
        if user_id:
            data = WxUserSerializer(instance=WxUser.objects.filter(pk=user_id).first()).data
        return APIResponse(data=data, code=200)

    def post(self, request):
        user_id = get_user_id(self)
        if user_id:
            instance = WxUser.objects.filter(pk=user_id).first()
            serializer = self.get_serializer(instance, data=request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return APIResponse(data=serializer.data, code=200)
        return APIResponse(code=401)


class GetWxTokenView(GenericAPIView):
    authentication_classes = []
    permission_classes = []
    pagination_class = None
    filter_backends = []
    serializer_class = GetWxTokenSerializer

    def get(self, request):
        token = 'jiaozi2021'
        signature = request.query_params.get('signature', '')
        nonce = request.query_params.get('nonce', '')
        timestamp = request.query_params.get('timestamp', '')
        echostr = request.query_params.get('echostr', '')
        ls = [token, timestamp, nonce]
        ls.sort()
        sha1 = hashlib.sha1()
        sha1.update(ls[0].encode('utf-8'))
        sha1.update(ls[1].encode('utf-8'))
        sha1.update(ls[2].encode('utf-8'))
        hashcode = sha1.hexdigest()
        print(signature, hashcode)
        if signature == hashcode:
            return Response(data={'echostr': echostr})
        else:
            return APIResponse(data=echostr, code=400, message='error')
